/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.openide.loaders;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.datatransfer.*;
import java.beans.*;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import java.util.ResourceBundle;
import org.openide.filesystems.FileSystem;
import org.openide.filesystems.FileStatusListener;
import org.openide.filesystems.FileStatusEvent;
import org.openide.filesystems.FileStateInvalidException;
import org.openide.filesystems.FileObject;
import org.openide.util.datatransfer.*;
import org.openide.actions.InstantiateAction;
import org.openide.util.HelpCtx;
import org.openide.util.RequestProcessor;
import org.openide.util.NbBundle;
import org.openide.util.WeakListener;
import org.openide.util.actions.SystemAction;
import org.openide.nodes.*;
/** Standard node representing a data object.
*
* @author Jaroslav Tulach
*/
public class DataNode extends AbstractNode {
/** generated Serialized Version UID */
static final long serialVersionUID = -7882925922830244768L;
/** default base for icons for data objects */
private static final String ICON_BASE = "/org/netbeans/core/resources/x"; // NOI18N
/** DataObject of this node. */
private DataObject obj;
/** property change listener */
private PropL propL;
/** Create a data node for a given data object.
* The provided children object will be used to hold all child nodes.
* @param obj object to work with
* @param ch children container for the node
*/
public DataNode (DataObject obj, Children ch) {
super (ch);
this.obj = obj;
propL = new PropL ();
obj.addPropertyChangeListener (WeakListener.propertyChange (propL, obj));
super.setName (obj.getName ());
setIconBase (ICON_BASE);
}
/** Get the represented data object.
* @return the data object
*/
public DataObject getDataObject() {
return obj;
}
/* Changes the name of the node and also renames the data object.
*
* @param name new name for the object
* @param rename rename the data object?
* @exception IllegalArgumentException if the rename failed
*/
public void setName (String name, boolean rename) {
try {
if (rename) {
obj.rename (name);
}
super.setName (name);
} catch (IOException ex) {
throw new IllegalArgumentException (ex.getMessage ());
}
}
/* Rename the data object.
* @param name new name for the object
* @exception IllegalArgumentException if the rename failed
*/
public void setName (String name) {
setName (name, true);
}
/** Get the display name for the node.
* A filesystem may {@link org.openide.filesystems.FileSystem#getStatus specially alter} this.
* @return the desired name
*/
public String getDisplayName () {
String s = super.getDisplayName ();
try {
s = obj.getPrimaryFile ().getFileSystem ().getStatus ().annotateName (s, obj.files ());
} catch (FileStateInvalidException e) {
// no fs, do nothing
}
return s;
}
/** Get the displayed icon for this node.
* A filesystem may {@link org.openide.filesystems.FileSystem#getStatus specially alter} this.
* @param type the icon type from {@link java.beans.BeanInfo}
* @return the desired icon
*/
public java.awt.Image getIcon (int type) {
java.awt.Image img = super.getIcon (type);
try {
img = obj.getPrimaryFile ().getFileSystem ().getStatus ().annotateIcon (img, type, obj.files ());
} catch (FileStateInvalidException e) {
// no fs, do nothing
}
return img;
}
public HelpCtx getHelpCtx () {
return obj.getHelpCtx ();
}
/** Indicate whether the node may be renamed.
* @return tests {@link DataObject#isRenameAllowed}
*/
public boolean canRename () {
return obj.isRenameAllowed ();
}
/** Indicate whether the node may be destroyed.
* @return tests {@link DataObject#isDeleteAllowed}
*/
public boolean canDestroy () {
return obj.isDeleteAllowed ();
}
/* Destroyes the node
*/
public void destroy () throws IOException {
if (obj.isDeleteAllowed ()) {
obj.delete ();
}
super.destroy ();
}
/* Returns true if this object allows copying.
* @returns true if this object allows copying.
*/
public final boolean canCopy () {
return obj.isCopyAllowed ();
}
/* Returns true if this object allows cutting.
* @returns true if this object allows cutting.
*/
public final boolean canCut () {
return obj.isMoveAllowed ();
}
/** This method returns null to signal that actions
* provide by DataLoader.getActions should be returned from
* method getActions. If overriden to provide some actions,
* then these actions will be preferred to the loader's ones.
*
* @return null
*/
protected SystemAction[] createActions () {
return null;
}
/** Get actions for this data object.
* @see DataLoader#getActions
* @return array of actions or <code>null</code>
*/
public SystemAction[] getActions () {
if (systemActions == null) {
systemActions = createActions ();
}
if (systemActions != null) {
return systemActions;
}
return obj.getLoader ().getActions ();
}
/** Get default action.
* A data node may have a {@link InstantiateAction default action} if it represents a template.
* @return an instantiation action if the underlying data object is a template. Otherwise the abstract node's default action is returned, possibly <code>null</code>.
*/
public SystemAction getDefaultAction () {
if (obj.isTemplate ()) {
return SystemAction.get (InstantiateAction.class);
} else {
return super.getDefaultAction ();
}
}
/** Get a cookie.
* First of all {@link DataObject#getCookie} is
* called. If it produces non-<code>null</code> result, that is returned.
* Otherwise the superclass is tried.
*
* @return the cookie or <code>null</code>
*/
public Node.Cookie getCookie (Class cl) {
Node.Cookie c = obj.getCookie (cl);
if (c != null) {
return c;
} else {
return super.getCookie (cl);
}
}
/* Initializes sheet of properties. Allow subclasses to
* overwrite it.
* @return the default sheet to use
*/
protected Sheet createSheet () {
Sheet s = Sheet.createDefault ();
Sheet.Set ss = s.get (Sheet.PROPERTIES);
Node.Property p;
p = createNameProperty (obj);
p.setName (DataObject.PROP_NAME);
ss.put (p);
try {
p = new PropertySupport.Reflection (
obj, Boolean.TYPE, "isTemplate", "setTemplate" // NOI18N
);
p.setName (DataObject.PROP_TEMPLATE);
p.setDisplayName (DataObject.getString("PROP_template"));
p.setShortDescription (DataObject.getString("HINT_template"));
ss.put (p);
} catch (Exception ex) {
throw new InternalError ();
}
return s;
}
/** Creates a name property for given data object.
*/
static Node.Property createNameProperty (final DataObject obj) {
Node.Property p = new PropertySupport.ReadWrite (
DataObject.PROP_NAME,
String.class,
DataObject.getString("PROP_name"),
DataObject.getString("HINT_name")
) {
public Object getValue () {
return obj.getName();
}
public void setValue (Object val) throws IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
if (!canWrite())
throw new IllegalAccessException();
if (!(val instanceof String))
throw new IllegalArgumentException();
try {
obj.rename ((String)val);
} catch (IOException ex) {
throw new InvocationTargetException (ex);
}
}
public boolean canWrite () {
return obj.isRenameAllowed();
}
};
return p;
}
/** Support for firing property change.
* @param ev event describing the change
*/
void fireChange (PropertyChangeEvent ev) {
firePropertyChange (ev.getPropertyName (), ev.getOldValue (), ev.getNewValue ());
if (ev.getPropertyName ().equals (DataObject.PROP_NAME)) {
super.setName (obj.getName ());
return;
}
if (ev.getPropertyName ().equals (DataObject.PROP_COOKIE)) {
fireCookieChange ();
}
}
/** Handle for location of given data object.
* @return handle that remembers the data object.
*/
public Handle getHandle () {
return new ObjectHandle (obj, this != obj.getNodeDelegate ());
}
/** Access method to fire icon change.
*/
final void fireChangeAccess (boolean icon, boolean name) {
if (name) {
fireDisplayNameChange (null, null);
}
if (icon) {
fireIconChange ();
}
}
/** Property listener on data object that delegates all changes of
* properties to this node.
*/
private class PropL extends Object
implements PropertyChangeListener, FileStatusListener {
/** weak version of this listener */
private FileStatusListener weakL;
/** previous file system we were attached to */
private FileSystem previous;
public PropL () {
updateStatusListener ();
}
public void propertyChange (PropertyChangeEvent ev) {
if (DataFolder.PROP_CHILDREN.equals (ev.getPropertyName ())) {
// the node is not interested in children changes
return;
}
if (DataFolder.PROP_PRIMARY_FILE.equals (ev.getPropertyName ())) {
// the node is not interested in children changes
updateStatusListener ();
setName (obj.getName (), false);
return;
}
fireChange (ev);
}
/** Updates listening on a status of file system.
*/
private void updateStatusListener () {
if (previous != null) {
previous.removeFileStatusListener (weakL);
}
try {
previous = obj.getPrimaryFile ().getFileSystem ();
if (weakL == null) {
weakL = WeakListener.fileStatus (this, null);
}
previous.addFileStatusListener (weakL);
} catch (FileStateInvalidException ex) {
previous = null;
}
}
/** Notifies listener about change in annotataion of a few files.
* @param ev event describing the change
*/
public void annotationChanged (FileStatusEvent ev) {
if (ev.hasChanged (obj.getPrimaryFile ())) {
fireChangeAccess (ev.isIconChange (), ev.isNameChange ());
}
}
}
/** Handle for data object nodes */
private static class ObjectHandle extends Object implements Handle {
private FileObject obj;
private boolean clone;
static final long serialVersionUID =6616060729084681518L;
public ObjectHandle (DataObject obj, boolean clone) {
this.obj = obj.getPrimaryFile ();
this.clone = clone;
}
public Node getNode () throws DataObjectNotFoundException {
Node n = DataObject.find (obj).getNodeDelegate ();
return clone ? n.cloneNode () : n;
}
}
}
/*
* Log
* 32 Gandalf 1.31 1/20/00 Jaroslav Tulach Less access to disk.
* 31 Gandalf 1.30 1/15/00 Jaroslav Tulach DataShadow enhancements
* 30 Gandalf 1.29 1/12/00 Ian Formanek NOI18N
* 29 Gandalf 1.28 11/29/99 Jaroslav Tulach Weaker + setName
* (String, boolean)
* 28 Gandalf 1.27 11/5/99 Jaroslav Tulach WeakListener has now
* registration methods.
* 27 Gandalf 1.26 10/29/99 Jaroslav Tulach MultiFileSystem +
* FileStatusEvent
* 26 Gandalf 1.25 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 25 Gandalf 1.24 9/25/99 Jaroslav Tulach #2152
* 24 Gandalf 1.23 9/10/99 Jaroslav Tulach Annotate improvement
* 23 Gandalf 1.22 9/1/99 Jaroslav Tulach The DataNode reacts to
* changes in FileSystem.getStatus by updating its name and icon.
* 22 Gandalf 1.21 8/18/99 Ian Formanek Generated serial version
* UID
* 21 Gandalf 1.20 7/29/99 Jaroslav Tulach createActions can be
* overriden and it does something
* 20 Gandalf 1.19 7/23/99 Jesse Glick Removing helpCtx
* property from data nodes.
* 19 Gandalf 1.18 6/24/99 Jesse Glick Help context pulled from
* data object.
* 18 Gandalf 1.17 6/9/99 Jaroslav Tulach Executables can be in
* menu & toolbars.
* 17 Gandalf 1.16 6/8/99 Ian Formanek ---- Package Change To
* org.openide ----
* 16 Gandalf 1.15 5/10/99 Jesse Glick [JavaDoc]
* 15 Gandalf 1.14 5/10/99 Jaroslav Tulach DataNode.canRename
* 14 Gandalf 1.13 5/9/99 Ian Formanek Fixed bug 1651 - Rename
* action in popup menu of package is always disabled, renaming by "Name"
* field in property sheet works.
* 13 Gandalf 1.12 4/23/99 Jaroslav Tulach Handle implemented.
* 12 Gandalf 1.11 4/5/99 Ian Formanek Removed obsoleted import
* 11 Gandalf 1.10 3/16/99 Jesse Glick [JavaDoc]
* 10 Gandalf 1.9 3/15/99 Jesse Glick [JavaDoc]
* 9 Gandalf 1.8 3/13/99 Jaroslav Tulach FileSystem.Status &
* lastModified
* 8 Gandalf 1.7 3/10/99 Jesse Glick [JavaDoc]
* 7 Gandalf 1.6 3/9/99 Jesse Glick [JavaDoc]
* 6 Gandalf 1.5 2/5/99 Jaroslav Tulach Changed new from
* template action
* 5 Gandalf 1.4 1/21/99 Ales Novak
* 4 Gandalf 1.3 1/7/99 Jaroslav Tulach
* 3 Gandalf 1.2 1/7/99 Ian Formanek fixed resource names
* 2 Gandalf 1.1 1/6/99 Jaroslav Tulach Change of package of
* DataObject
* 1 Gandalf 1.0 1/5/99 Ian Formanek
* $
* Beta Change History:
* 0 Tuborg 0.11 --/--/98 Jaroslav Tulach actions are lookuped in the loaders pool
* 0 Tuborg 0.12 --/--/98 Ales Novak Serializable
* 0 Tuborg 0.13 --/--/98 Jaroslav Tulach default action for templates
*/